Skip to content

Method: areEqualMask(int, int)

1: package de.fhdw.gaming.ipspiel23.c4.domain.impl.evaluation;
2:
3: import java.util.Set;
4:
5: import de.fhdw.gaming.ipspiel23.c4.domain.C4Direction;
6: import de.fhdw.gaming.ipspiel23.c4.domain.IC4SolutionSlim;
7: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim;
8: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4SolutionSlim;
9:
10: import static de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim.EMPTY_TOKEN;
11:
12: /**
13: * Represents a solution analyzer that scans the board in a specific direction.
14: * <p>
15: * Note: This is an internal API that may be subject to incompatible changes in future releases.
16: * </p>
17: */
18: public abstract class C4SolutionAnalyzer {
19:
20: /**
21: * The direction in which the board is scanned.
22: */
23: private final C4Direction searchDirection;
24:
25: /**
26: * The board that is scanned.
27: */
28: private final C4BoardSlim boardField;
29:
30: /**
31: * A local copy of the board's row count for quicker access.
32: */
33: private final int rowMaxField;
34:
35: /**
36: * A local copy of the board's column count for quicker access.
37: */
38: private final int colMaxField;
39:
40: /**
41: * The internal number of tokens that need to be matched to form a solution.
42: */
43: private final int targetCountField;
44:
45: /**
46: * Creates a new instance of {@link C4SolutionAnalyzer}.
47: * @param board The board that is scanned.
48: * @param searchDirection The direction in which the board is scanned.
49: */
50: protected C4SolutionAnalyzer(final C4BoardSlim board, final C4Direction searchDirection) {
51: this.searchDirection = searchDirection;
52: this.boardField = board;
53: this.rowMaxField = board.getRowCount();
54: this.colMaxField = board.getColumnCount();
55: this.targetCountField = board.getMinimumSolutionSize() - 1;
56: }
57:
58: /**
59: * Lazily searches for the first solution on the board if the current solution is null.
60: * @param currentSolution The current solution.
61: * @param updateCache Whether to update the solution cache, preventing the same line to be checked again.
62: * @return The first solution on the board or null if no solution was found.
63: */
64: public abstract IC4SolutionSlim tryFindFirstSolution(IC4SolutionSlim currentSolution, boolean updateCache);
65:
66: /**
67: * Eagerly searches for all solutions on the board and adds them to the result set.
68: * @param resultSet The result set to which the solutions are added, if any.
69: * @param updateCache Whether to update the solution cache, preventing the same line to be checked again.
70: */
71: public abstract void findAllSolutions(Set<IC4SolutionSlim> resultSet, boolean updateCache);
72:
73: /**
74: * The direction in which the board is scanned.
75: */
76: public C4Direction getSearchDirection() {
77: return this.searchDirection;
78: }
79:
80: /**
81: * The board that is scanned.
82: */
83: protected C4BoardSlim board() {
84: return this.boardField;
85: }
86:
87: /**
88: * Resets the internal cache.
89: */
90: public abstract void resetCache();
91:
92: /**
93: * A local copy of the board's row count for quicker access.
94: */
95: protected int rowMax() {
96: return this.rowMaxField;
97: }
98:
99: /**
100: * A local copy of the board's column count for quicker access.
101: */
102: protected int colMax() {
103: return this.colMaxField;
104: }
105:
106: /**
107: * The internal number of tokens that need to be matched to form a solution.
108: */
109: protected int targetCount() {
110: return this.targetCountField;
111: }
112:
113: /**
114: * Creates a new solution instance.
115: * @param token The token that forms the solution.
116: * @param matchEndRow The row index of the last token in the solution.
117: * @param matchEndCol The column index of the last token in the solution.
118: * @param size The number of tokens in the solution.
119: * @return A new solution instance.
120: */
121: protected C4SolutionSlim solutionOf(final int token, final int matchEndRow,
122: final int matchEndCol, final int size) {
123: return new C4SolutionSlim(boardField, token, matchEndRow, matchEndCol, this.searchDirection, size);
124: }
125:
126: /**
127: * Scans any additional tokens that belong to an already identified solution.
128: * @param token The token that forms the solution.
129: * @param row The row index of the last scanned token in the solution.
130: * @param col The column index of the last scanned token in the solution.
131: * @return The solution containing any additional tokens.
132: */
133: protected abstract C4SolutionSlim scanRemaining(int token, int row, int col);
134:
135: /**
136: * Calculates the number of consecutive tokens with the same value without branching (prevent CPU pipeline stalls)
137: * Returns count + 1 if the current token has the same value as the previous one AND
138: * the previous token was not 0, otherwise returns 0.
139: * @param count The current number of consecutive tokens with the same value.
140: * @param token The value of the current token.
141: * @param previousToken The value of the previous token.
142: * @return count + 1 if token == previousToken and previousToken != EMPTY_TOKEN else 0
143: */
144: protected static int countConsecutivesBranchless(final int count, final int token, final int previousToken) {
145: // I hope this gets inlined by the JIT :)
146: // this implements: return 0 + (token == previousToken && previousToken != EMPTY_TOKEN ? count + 1 : 0);
147: // return 0 by default
148: return 0
149: // ... and add count + 1 ...
150: + ((count + 1)
151: // ... IFF the previous token has a value other than EMPTY_TOKEN ...
152: & areNotEqualMask(previousToken, EMPTY_TOKEN)
153: // ... AND the tokens are equal.
154: & areEqualMask(token, previousToken));
155: }
156:
157: /**
158: * without branching, checks if {@code a} and {@code b} are not equal, returning the corresponding bit mask.
159: * @param value1 the first value
160: * @param value2 the other value
161: * @return {@code -1 (TRUE)} iff a and b are not equal, {@code 0 (FALSE)} otherwise
162: */
163: protected static int areNotEqualMask(final int value1, final int value2) {
164: return (-(value1 ^ value2)) >> 31;
165: }
166:
167: /**
168: * without branching, checks if {@code a} and {@code b} are equal, returning the corresponding bit mask.
169: * @param value1 the first value
170: * @param value2 the other value
171: * @return {@code -1 (TRUE)} iff a and b are equal, {@code 0 (FALSE)} otherwise
172: */
173: protected static int areEqualMask(final int value1, final int value2) {
174: return ~areNotEqualMask(value1, value2);
175: }
176: }